import Queue
import threading, time
import copy
from BruTile.TileSchema import TileSchema
from BruTile.TileInfo import TileInfo
from UI.Fetcher.TileFetcher import TileFetcher
from BruTile.AxisInvertedY import AxisInvertedY
from BruTile.TileRange import TileRange
from BruTile.Cache.MemoryCache import MemoryCache

'''
# <summary>
# Contians all information about a tile layer and tile seed and provides methods to process tile seeds
# </summary>
'''

class TileSeed(threading.Thread):
    
    tile_schema = None
    seed_schema = None
    tile_fetcher = None
    href = ""
    
    __seedExtent = None
    __seedZoomLvl = []
    
    __update_queue = None
    __quit_queue = None
    
    tilesdone = 0
    totaltiles = 0
    tilesfailed = 0
    tilesremaining = 0
    
    TimeAverage = 0.0
    TimeRemaining = 0.0
    
    active = False
    __quit = False
    
    def __init__(self):
        self.__update_queue = Queue.Queue()
        self.__quit_queue = Queue.Queue()
        self.seed_schema = TileSchema()
    
    def HasSeedInfo(self):
        if not self.seed_schema.extent is None:
            if len(self.seed_schema.resolutions) > 0:
                return True
        return False
    
    def SetSeedZoomLvl(self, resolutions):
        if len(self.seed_schema.resolutions) == 0:
            self.seed_schema.resolutions = resolutions[:]
    
    def HasLayerInfo(self):
        if not self.tile_schema is None:
            if len(self.tile_schema.resolutions) > 0:
                return True
        
        return False
    
    def AddSeedZoomLvl(self, level):
        self.seed_schema.resolutions.append(copy.copy(level))
        self.seed_schema.resolutions.sort(cmp=None, key=None, reverse=False)
    
    def RemoveSeedZoomLvl(self, level):
        for i in range(0,len(self.seed_schema.resolutions)):
            item = self.seed_schema.resolutions[i]
            if item[0] == level:
                try:
                    self.seed_schema.resolutions.pop(i)
                    return
                except IndexError:
                    print("No Index")
    
    '''
    def GetSeedZoomLvl(self):
        return self.__seedZoomLvl
    
    def GetSeedExtent(self):
        return self.__seedExtent
    '''
    def SetSeedExtent(self, extent):
        if not self.seed_schema.extent.isValid() or not extent.equals(self.tile_schema.extent):
            #self.__seedExtent = extent
            self.seed_schema.extent = extent
            
    def SetAttributes(self, schemaCopy, seedCopy):
        self.tile_schema = schemaCopy
        self.href = self.tile_schema.getHref()
        self.seed_schema = seedCopy
        '''if not (att[2] is None):
            self.seed_schema.extent = att[2]
            self.seed_schema.resolutions = att[3]
        '''
        self.SetThreadName()
    '''
    def SetAttributes(self, att):
        self.tile_schema = att[0]
        self.href = att[1]
        if not (att[2] is None):
            self.seed_schema.extent = att[2]
            self.seed_schema.resolutions = att[3]
        self.SetThreadName()
    '''
    
    def GetAttributes(self):
        attributes = []
        attributes.append(self.tile_schema)
        attributes.append(self.href)
        if not (self.seed_schema is None):
            attributes.append(self.seed_schema.extent)
            attributes.append(self.seed_schema.resolutions)
        else:
            attributes.append(None)
            attributes.append(None)
        return copy.deepcopy(attributes)
    
    def SetSeedInfo(self, attributes, url):
        self.tile_schema = TileSchema()
        self.tile_schema.src = str(attributes.get("srs",""))
        self.tile_schema.name = str(attributes.get("title",""))
        self.href = url + self.tile_schema.name
        self.SetThreadName()
    
    def SetThreadName(self):
        threading.Thread.__init__(self, name="TileSeed: " + self.href)
    
    def GetUpdateQueue(self):
        return self.__update_queue
    
    def GetQuitQueue(self):
        return self.__quit_queue

    def run(self):
        print(threading.current_thread().getName())
        #self.href = "http://a.tile.openstreetmap.org"

        self.tile_fetcher = TileFetcher()
        self.tile_fetcher.InitSeedThread(self.tile_schema, self.href, self.QuitThread, self.UpdateLayerInfo)
        self.totaltiles = self.GetNrTilesForTileSeed()
        
        for resolution in self.seed_schema.resolutions:
            if not self.__quit:
                self.GetTilesInView(self.seed_schema.extent, resolution)
            else:
                return
    
    def QuitThread(self):
        self.__quit = True
    
    def UpdateLayerInfo(self, tile_info, is_failed):
        self.ClearUpdateQue()
        
        self.tilesdone += 1
        
        if (is_failed):
            self.tilesfailed += 1
        
        percentage = (self.tilesdone/self.totaltiles)*100

        if (self.__quit_queue.empty()):
            values = [self.tile_schema.name, self.tilesfailed, percentage, self.tilesdone, self.totaltiles]
            #print("TileSeed: UpdateLayer")
            self.__update_queue.put(values)
    
    def ClearUpdateQue(self):
        while not self.__update_queue.empty():
            self.__update_queue.get()
    
    def GetTilesInView(self, extent, resolution):
        level = resolution[0]
        axisInverted = AxisInvertedY()
        tileRange = axisInverted.worldToTile(extent, level, self.tile_schema)
        
        for x in range(int(tileRange.getFirstCol()), int(tileRange.getLastCol())):            
            for y in range(int(tileRange.getFirstRow()), int(tileRange.getLastRow())):
                if not self.__quit:
                    tile = TileInfo()
                    tile.extent = axisInverted.tileToWorld(TileRange(x,y,x,y), level, self.tile_schema)
                    tile.key = (x,y,level)
                    if (self.tile_schema.withinSchemaExtent(self.tile_schema.extent, tile.extent)):
                        if (self.__quit_queue.empty()):
                            self.tile_fetcher.fetchOnThread(tile)
                        else:
                            inProcess = True
                            while inProcess:
                                inProcess = self.tile_fetcher.TilesInProcess(self.href)
                                time.sleep(0.1)
                            self.__quit = True
                else:
                    print("TileSeed "+ str(self.href) +": Quit")
                    return

    def GetNrTilesForTileSeed(self):
        nrOfTiles = 0.0
        for resolution in self.seed_schema.resolutions:
            resolution = resolution[1]
            nr_tiles = self.tile_schema.getTilesRange(self.seed_schema.extent, resolution)
            nrOfTiles += (nr_tiles[0] * nr_tiles[1])

        return nrOfTiles
    
    def _print(self, prefix):
        print(prefix + " href = " + self.href)
        print(prefix + " name = " + self.tile_schema.name)
        print(prefix + " src = " + self.tile_schema.src)